//
// Created by MI T on 2024/8/1.
//

#include "UvcPreview.h"
#include "CameraParameterState.h"
#include "PluginManager.h"
#include <cstdint>
#include <future>
#include <sstream>
#include "img_util.h"

UvcPreview::UvcPreview(uvc_device_handle_t *deviceHandler)
    : mDeviceHandle(deviceHandler), mDisplayTransformState(TRANSFORM_IDENTITY), frameMode(UVC_FORMAT_YUY2),
      requestWidth(DEFAULT_PREVIEW_WIDTH), requestHeight(DEFAULT_PREVIEW_HEIGHT), requestMode(UVC_REQUEST_FORMAT_RGBA),
      frameBytes(DEFAULT_PREVIEW_WIDTH * DEFAULT_PREVIEW_HEIGHT * 2), mIsRunning(false), mSurfaceId(nullptr),
      func(nullptr) {
    // 初始化互斥锁
    pthread_mutex_init(&captureMutex, nullptr);
    pthread_cond_init(&captureCond, nullptr);

    pthread_mutex_init(&surfaceMutex, nullptr);
}

UvcPreview::~UvcPreview() {
    pthread_mutex_destroy(&captureMutex);
    pthread_cond_destroy(&captureCond);

    pthread_mutex_destroy(&surfaceMutex);

    free_napi(mSurfaceId);
    if (func) {
        napi_release_threadsafe_function(func, napi_tsfn_release);
    }
    func = nullptr;
    mDeviceHandle = nullptr;
}

int UvcPreview::startPreview() {
    uvc_stream_ctrl_t ctrl;
    int ret = prepare_preview(&ctrl);
    if (ret != UVC_SUCCESS) {
        return ret;
    }
    ret = do_preview(&ctrl);
    return ret;
}

int UvcPreview::prepare_preview(uvc_stream_ctrl_t *ctrl) {
    LOG_D("获取对应的流控制器-size:%{public}d-%{public}d", requestWidth, requestHeight);
    uvc_error_t ret = uvc_get_stream(mDeviceHandle, ctrl, getPreviewFormat(), requestWidth, requestHeight);
    LOG_D("获取对应的流控制器-结果:%{public}d", ret);
    if (ret != UVC_SUCCESS) {
        return ret;
    }
    LOG_D("当前设置的fps为:%{public}d", 10000000 / ctrl->dwFrameInterval);
    // 获取当前预览流需要设置的宽高等数据
    uvc_frame_desc_t *frameDesc = uvc_get_frame_desc(mDeviceHandle, ctrl);
    if (frameDesc) {
        frameWidth = frameDesc->wWidth;
        frameHeight = frameDesc->wHeight;
    } else {
        frameWidth = requestWidth;
        frameHeight = requestHeight;
    }
    frameBytes = getPreviewBytesSize();
    PluginWindowRender *render = loadRender();
    if (render) {
        render->initSize(frameWidth, frameHeight);
    }
    return UVC_SUCCESS;
}

int UvcPreview::do_preview(uvc_stream_ctrl_t *ctrl) {
    clearCaptureFrame();
    uvc_error_t ret = uvc_start_streaming(mDeviceHandle, ctrl, uvc_stream_callback, (void *)this, 0);
    LOG_D("开启预览流-结果:%{public}d", ret);
    if (ret != UVC_SUCCESS) {
        return ret;
    }
    // 开启线程，启动捕获流操作
    mIsRunning = true;
    int result = pthread_create(&captureThread, nullptr, capture_thread_func, (void *)this);
    LOG_D("创建捕获数据线程结果-结果:%{public}d", result);
    return ret;
}

// 预览流回调的实际数据
void UvcPreview::uvc_stream_callback(uvc_frame_t *frame, void *vptr_args) {
    // 获取当前的uvcPreview对象
    auto *preview = reinterpret_cast<UvcPreview *>(vptr_args);
    // 如果当前不是正在预览，或者当前数据返回的是null，则直接下一回合
    if (!preview->mIsRunning || !frame) {
        LOG_E("当前数据返回的是null，则直接下一回合：：%{public}d", preview->mIsRunning);
        return;
    }
    if (!(frame->width == preview->frameWidth && frame->height == preview->frameHeight) &&
        !(frame->width == preview->frameHeight && frame->height == preview->frameWidth)) {
        LOG_E("当前数据宽高不符");
        return;
    }
    uvc_frame_format format = frame->frame_format;
    if (!format || (format != UVC_FRAME_FORMAT_MJPEG && format != UVC_FRAME_FORMAT_YUYV)) {
        LOG_E("当前数据格式错误.metadata_bytes:%{public}zu", frame->metadata_bytes);
        return;
    }
    if ((format != UVC_FRAME_FORMAT_MJPEG && frame->data_bytes < preview->frameBytes) || !frame->data) {
        LOG_E("当前数据大小不符合；；data_bytes:%{public}zu,frameBytes:%{public}zu", frame->data_bytes,
              preview->frameBytes);
        return;
    }
    //    //获取bgr类型的数据数组
    uvc_frame_t *rgbaFrame = uvc_allocate_frame(frame->width * frame->height * 4);
    if (!rgbaFrame) {
        LOG_E("创建rgba对象失败");
        return;
    }
    // 将数据转换成rgb格式
    if (!ImgUtils::any2Rgba(frame, rgbaFrame)) {
        LOG_E("数据转换失败");
        uvc_free_frame(rgbaFrame);
        return;
    }
    preview->drawFrame(rgbaFrame);
//     数据发送出去
    preview->putFrame(rgbaFrame);
}

void *UvcPreview::capture_thread_func(void *vptr_args) {
    auto *preview = reinterpret_cast<UvcPreview *>(vptr_args);
    LOG_E("=====开启循环读取预览帧");
    if (preview) {
        LOG_E("=====mIsRunning：：：%{public}d", preview->mIsRunning);
        while (preview->mIsRunning) {
            // 等待获取预览的数据
            uvc_frame_t *pFrame = preview->waitPreviewFrame();
            if (!pFrame) {
                continue;
            }
            uvc_frame_t *outData;
            // 是否需要删除旧的数据
            if (preview->requestMode == UVC_REQUEST_FORMAT_NV21) {
                outData = ImgUtils::rgba2Nv21(pFrame);
                uvc_free_frame(pFrame); // 删除旧数据缓存
            } else {
                outData = pFrame;
            }
            FrameData *data = new FrameData{outData};
            if (!preview->func ||
                napi_call_threadsafe_function(preview->func, data, napi_tsfn_nonblocking) != napi_ok) {
                LOG_E("当前未设置预览监听，或者未不需要触发回调设置");
                uvc_free_frame(outData);
                delete data;
            };
        }
    }
    pthread_exit(nullptr);
}


void UvcPreview::drawFrame(uvc_frame_t *frame) {
    pthread_mutex_lock(&surfaceMutex);
    {
        PluginWindowRender *render = loadRender();
        if (render && frame) {
            render->drawFrame((uint8_t *)frame->data, frame->data_bytes, frame->width, frame->height);
        }
    }
    pthread_mutex_unlock(&surfaceMutex);
}

void UvcPreview::putFrame(uvc_frame_t *frame) {
    // 执行锁定
    pthread_mutex_lock(&captureMutex);
    // 如果缓存池的数据满了，则吧第一帧的数据删除掉
    if (mIsRunning && previewFrames.size() < MAX_FRAME) {
        previewFrames.put(frame);
        frame = nullptr;
    }
    pthread_cond_signal(&captureCond);
    pthread_mutex_unlock(&captureMutex);
    if (frame) {
        // 如果没有写入到缓存，则直接释放当前对象
        uvc_free_frame(frame);
    }
}

uvc_frame_t *UvcPreview::waitPreviewFrame() {
    uvc_frame_t *frame = nullptr;
    pthread_mutex_lock(&captureMutex);
    {
        // 如果当前内容为空，则等待获取数据，被唤醒
        if (previewFrames.isEmpty()) {
            pthread_cond_wait(&captureCond, &captureMutex);
        }
        // 如果当前是正在预览，并且预览数据大于0
        if (mIsRunning && !previewFrames.isEmpty()) {
            frame = previewFrames.remove(0);
        }
    }
    pthread_mutex_unlock(&captureMutex);
    return frame;
}

int UvcPreview::stopPreview() {
    LOG_D("停止预览开始");
    LOG_D("mIsRunning:%{public}d", mIsRunning);
    if (mIsRunning) {
        // 停止预览线程
        mIsRunning = false;
        uvc_stop_streaming(mDeviceHandle);
        pthread_cond_signal(&captureCond);
        if (pthread_join(captureThread, nullptr) != EXIT_SUCCESS) {
            LOG_E("UVCPreview::terminate capture thread: pthread_join failed");
        }
    }
    LOG_D("停止预览结束");
    clearCaptureFrame();
    return UVC_SUCCESS;
}

int UvcPreview::setPreviewSize(int width, int height, int format) {
    LOG_D("setPreviewSize-size:%{public}d*%{public}d", width, height);
    requestWidth = width;
    requestHeight = height;
    frameMode = format;
    uvc_stream_ctrl_t ctrl;
    // 设置完成后需要提前获取一次，否则打开时无法正常获取到流
    uvc_error_t ret = uvc_get_stream(mDeviceHandle, &ctrl, getPreviewFormat(), requestWidth, requestHeight);
    LOG_D("设置预览分辨率同步获取预览流-setPreviewSize-结果:%{public}d", ret);
    return UVC_SUCCESS;
}

int UvcPreview::setDisplaySurface(char *surfaceId) {
    pthread_mutex_lock(&surfaceMutex);
    {
        free_napi(mSurfaceId);  // 释放旧指针
        mSurfaceId = surfaceId; // 赋值新指针
    }
    pthread_mutex_unlock(&surfaceMutex);
    return UVC_SUCCESS;
}

PluginWindowRender *UvcPreview::loadRender() {
    if (!mSurfaceId) {
        return nullptr;
    }
    return PluginManager::GetInstance()->getRender(mSurfaceId);
}

void UvcPreview::clearCaptureFrame() {
    pthread_mutex_lock(&captureMutex);
    if (!previewFrames.isEmpty()) {
        for (int i = 0; i < previewFrames.size(); ++i) {
            uvc_frame_t *&pFrame = previewFrames[i];
            uvc_free_frame(pFrame);
        }
        previewFrames.clear();
    }
    pthread_mutex_unlock(&captureMutex);
}

void UvcPreview::preview_thread_call(napi_env env, napi_value jsCb, void *context, void *data) {
    FrameData *frameData = (FrameData *)data;
    uvc_frame_t *previewFrame = frameData->frame;
    if (!previewFrame) {
        delete frameData;
        return;
    }
    // 设置napi_value作用域
    napi_handle_scope scope;
    napi_open_handle_scope(env, &scope);
    napi_value widthValue = napiUtils::createIntNapi(env, previewFrame->width);
    napi_value heightValue = napiUtils::createIntNapi(env, previewFrame->height);
    napi_value bytes = napiUtils::createUint8Array(env, (uint8_t *)previewFrame->data, previewFrame->data_bytes);
    napi_value undefined;
    if (widthValue && widthValue && heightValue && napi_get_undefined(env, &undefined) == napi_ok) {
        napi_value argv[3] = {bytes, widthValue, heightValue};
        napi_call_function(env, undefined, jsCb, 3, argv, nullptr);
    } else {
        LOG_E("创建回调数据失败");
    }
    // 释放作用域
    napi_close_handle_scope(env, scope);
    uvc_free_frame(previewFrame);
    delete frameData;
}

bool UvcPreview::setDisplayTransformState(int transformState) {
    pthread_mutex_lock(&surfaceMutex);
    {
        mDisplayTransformState = transformState;
        auto render = loadRender();
        if (render) {
            render->setSurfaceTransformState(transformState);
        }
    }
    pthread_mutex_unlock(&surfaceMutex);
    return true;
}

void UvcPreview::setPreviewDataListener(napi_env env, napi_value value, int mode) {
    pthread_mutex_lock(&captureMutex);
    {
        this->requestMode = mode;
        if (func != nullptr) {
            napi_release_threadsafe_function(func, napi_tsfn_release);
            func = nullptr;
        }
        if (value) {
            napi_value resourseName = napiUtils::createStringNapi(env, "preview-thread");
            if (!resourseName ||
                napi_create_threadsafe_function(env, value, nullptr, resourseName, 0, 1, nullptr, nullptr, this,
                                                preview_thread_call, &func) != napi_ok) {
                func = nullptr;
            }
        }
    }
    pthread_mutex_unlock(&captureMutex);
}

int UvcPreview::getDisplayTransformState() { return mDisplayTransformState; }

int UvcPreview::getPreviewWidth() { return requestWidth; }
int UvcPreview::getPreviewHeight() { return requestHeight; }

int UvcPreview::loadCurrentFormat() { return frameMode; }

uvc_frame_format UvcPreview::getPreviewFormat() {
    switch (frameMode) {
    case UVC_FORMAT_MJPEG:
        return UVC_FRAME_FORMAT_MJPEG;
    case UVC_FORMAT_YUY2:
        return UVC_FRAME_FORMAT_YUYV;
    case UVC_FORMAT_NV12:
        return UVC_FRAME_FORMAT_NV12; // 扩展支持 NV12 格式
    case UVC_FORMAT_RGB:
        return UVC_FRAME_FORMAT_RGB; // 扩展支持 RGB 格式
    case UVC_FORMAT_BGR:
        return UVC_FRAME_FORMAT_BGR; // 扩展支持 BGR 格式
    default:
        return UVC_FRAME_FORMAT_YUYV;
    }
}

size_t UvcPreview::getPreviewBytesSize() {
    size_t previewSizes = frameWidth * frameHeight;
    switch (frameMode) {
    case UVC_FORMAT_MJPEG:
        return previewSizes;
    case UVC_FORMAT_YUY2:
        return previewSizes * 2;
    case UVC_FORMAT_NV12:
        return previewSizes * 3 / 2; // 扩展支持 NV12 格式
    case UVC_FORMAT_RGB:
        return previewSizes * 3; // 扩展支持 RGB 格式
    case UVC_FORMAT_BGR:
        return previewSizes * 3; // 扩展支持 BGR 格式
    default:
        return previewSizes * 2;
    }
}